package com.jiaxiaobang.majiang.majiang.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jiaxiaobang.majiang.majiang.core.TaskType;
import com.jiaxiaobang.majiang.majiang.entity.EquipmentStatus;
import com.jiaxiaobang.majiang.majiang.entity.EquipmentTask;
import com.jiaxiaobang.majiang.majiang.entity.QsgDevice;
import com.jiaxiaobang.majiang.majiang.entity.QsgRoom;
import com.jiaxiaobang.majiang.majiang.repository.EquipmentStatusRepository;
import com.jiaxiaobang.majiang.majiang.repository.EquipmentTaskRepository;
import com.jiaxiaobang.majiang.majiang.repository.QsgDeviceRepository;
import com.jiaxiaobang.majiang.majiang.repository.QsgRoomRepository;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class SocketHandler extends ChannelInboundHandlerAdapter{

//    public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static SocketHandler handler;

    @PostConstruct
    //因为是new出来的handler,没有托给spring容器,所以一定要先初始化,否则autowired失效
    public void init() {
        handler = this;
    }

    private Map<String, Channel> channelMap = new ConcurrentHashMap<>();

    @Resource
    private EquipmentStatusRepository equipmentStatusRepository;

    @Resource
    private EquipmentTaskRepository equipmentTaskRepository;

    @Resource
    private QsgDeviceRepository deviceRepository;

    @Resource
    private QsgRoomRepository roomRepository;
    /**
     * 读取到客户端发来的消息
     *
     * @param ctx ChannelHandlerContext
     * @param msg msg
     * @throws Exception e
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws InterruptedException {
        // 由于我们配置的是 字节数组 编解码器，所以这里取到的用户发来的数据是 byte数组
        String data = msg.toString();
        log.info("收到消息: " + new String(data));
        String result = "";
        boolean isOk = true;
        try{
            int start = data.indexOf("{");
            int end = data.indexOf("}");
            result = StringUtils.substring(data,start,end+1);
            log.info("截取后消息: " + result);
        }catch (Exception ex){
            log.error("消息格式错误：",ex.getMessage());
            isOk = false;
        }
        if(isOk){
            JSONObject equipment = JSON.parseObject(result);
            String equipmentId = equipment.getString("equipID");
            String responseType = equipment.getString("responseType");

            if(!channelMap.containsKey(equipmentId)){
                channelMap.put(equipmentId,ctx.channel());
            }

            //查询任务表，如果存在新的任务通知对应的设备
            if("HeartBeat".equalsIgnoreCase(responseType)){
                //更新设备状态
                EquipmentStatus statusInfo = new EquipmentStatus();
                statusInfo.setEquipmentId(equipmentId);
                Example<EquipmentStatus> example = Example.of(statusInfo);
                List<EquipmentStatus> current = handler.equipmentStatusRepository.findAll(example);
                if(null != current && !current.isEmpty()){
                    EquipmentStatus equip = current.get(0);
                    equip.setUpdateTime(new Date());
                    handler.equipmentStatusRepository.save(equip);
                }else{
                    EquipmentStatus equip = new EquipmentStatus();
                    equip.setEquipmentId(equipmentId);
                    equip.setStatus(0);
                    equip.setUpdateTime(new Date());
                    handler.equipmentStatusRepository.save(equip);
                }
            }
            if("Operation".equalsIgnoreCase(responseType)){
                String state = equipment.getString("state");
                if("success".equalsIgnoreCase(state)){
                    EquipmentTask taskInfo = new EquipmentTask();
                    String taskType = equipment.getString("taskType");
                    taskInfo.setEquipmentId(equipmentId);
                    taskInfo.setStatus(0);
                    if(Integer.parseInt(taskType) != 1){
                        taskInfo.setTaskType(Integer.parseInt(taskType));
                    }
                    Example<EquipmentTask> taskExample = Example.of(taskInfo);
                    List<EquipmentTask> currentTasks = handler.equipmentTaskRepository.findAll(taskExample);
                    if(null != currentTasks && !currentTasks.isEmpty()){
                        EquipmentTask current = currentTasks.get(0);
                        current.setStatus(1);
                        handler.equipmentTaskRepository.save(current);
                    }
                }
            }

            //验证板子是否断电导致任务失效   开始
            Specification<EquipmentTask> specifications = new Specification<EquipmentTask>() {
                @Override
                public Predicate toPredicate(Root<EquipmentTask> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> predicates = new ArrayList<>();
                    // 条件【查询所有登录名等于张三的用户】
                    predicates.add(criteriaBuilder.equal(root.get("equipmentId"), equipmentId));
                    predicates.add(criteriaBuilder.equal(root.get("status"), 0));
                    Date current = new Date();
                    predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("endTime"), current));
                    return query.where(criteriaBuilder.and(predicates.toArray(new Predicate[0]))).getGroupRestriction();
                }
            };

            List<EquipmentTask> existTasks = handler.equipmentTaskRepository.findAll(specifications);
            if(existTasks.size() > 1){
                for (EquipmentTask task: existTasks
                ) {
                    task.setStatus(1);
                    handler.equipmentTaskRepository.save(task);
                }
            }
            //验证板子是否断电导致任务失效   结束

            EquipmentTask taskInfo = new EquipmentTask();
            taskInfo.setEquipmentId(equipmentId);
            taskInfo.setStatus(0);
            Example<EquipmentTask> taskExample = Example.of(taskInfo);
            List<EquipmentTask> currentTasks = handler.equipmentTaskRepository.findAll(taskExample);
            if(null != currentTasks && !currentTasks.isEmpty()){
                for (EquipmentTask task: currentTasks
                ) {
                    Integer taskType = task.getTaskType();
                    //剩余30分钟语音播报,剩余5分钟语音播报,结束
                    if(TaskType.HALFHOUR_NOTICE_TASK.getType() == taskType.intValue() || TaskType.FIVEMINUTE_NOTICE_TASK.getType() == taskType.intValue() || TaskType.END_TASK.getType() == taskType.intValue()){
                        Date endTime = task.getEndTime();
                        if(null != endTime){
                            Date current = new Date();
//                        Date compareTime = DateUtil.strToDate(endTime,"yyyy-MM-dd HH:mm:ss");
                            Date compareTime = endTime;
                            if(current.after(compareTime)){
                                Channel ch = channelMap.get(equipmentId);
                                if(TaskType.HALFHOUR_NOTICE_TASK.getType() == taskType.intValue() || TaskType.FIVEMINUTE_NOTICE_TASK.getType() == taskType.intValue()){
                                    JSONObject message = new JSONObject();
                                    message.put("equipmentId",equipmentId);
                                    message.put("type",String.valueOf(taskType));
                                    ch.writeAndFlush(message.toJSONString());
                                }
                                if(TaskType.END_TASK.getType() == taskType.intValue()){
                                    JSONObject closeMsg = new JSONObject();
                                    closeMsg.put("equipmentId",equipmentId);
                                    closeMsg.put("type",String.valueOf(1));
                                    ch.writeAndFlush(closeMsg.toJSONString());
                                    task.setStatus(1);
                                    handler.equipmentTaskRepository.save(task);
                                    QsgDevice param = new QsgDevice();
                                    param.setDeviceCode(equipmentId);
                                    Example<QsgDevice> deviceParam = Example.of(param);
                                    List<QsgDevice> devices = handler.deviceRepository.findAll(deviceParam);
                                    if(null != devices && !devices.isEmpty()){
                                        Long deviceId = devices.get(0).getId();
                                        QsgRoom roomParam = new QsgRoom();
                                        roomParam.setDeviceId(deviceId);
                                        Example<QsgRoom> roomExample = Example.of(roomParam);
                                        List<QsgRoom> rooms  = handler.roomRepository.findAll(roomExample);
                                        if(null != rooms && !rooms.isEmpty()){
                                            QsgRoom currentRoom = rooms.get(0);
                                            currentRoom.setStatus(2);
                                            currentRoom.setBeforeStatus(2);
                                            handler.roomRepository.save(currentRoom);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else if(TaskType.OPEN_TASK.getType() == taskType.intValue()){
                        Channel ch = channelMap.get(equipmentId);
                        JSONObject message = new JSONObject();
                        message.put("equipmentId",equipmentId);
                        message.put("type",String.valueOf(0));
                        ch.writeAndFlush(message.toJSONString());
                        task.setStatus(1);
                        handler.equipmentTaskRepository.save(task);
                    }else if(TaskType.CLOSE_TASK.getType() == taskType.intValue()){
                        Channel ch = channelMap.get(equipmentId);
                        JSONObject message = new JSONObject();
                        message.put("equipmentId",equipmentId);
                        message.put("type",String.valueOf(1));
                        ch.writeAndFlush(message.toJSONString());
                        task.setStatus(1);
                        handler.equipmentTaskRepository.save(task);
                    }
                }
            }
        }

//        // 给其他人转发消息
//        for (Channel client : clients) {
//            if (!client.equals(ctx.channel())) {
//                client.writeAndFlush(data);
//            }
//        }
//        String result = "{\"result\":\"success\",\"msg\":\"1\"}";
//        ByteBuf buf = Unpooled.buffer();
//        buf.writeBytes(result.getBytes());
//        ctx.channel().writeAndFlush(buf);

//        ByteBuf buf2 = Unpooled.buffer();
//        buf2.writeBytes("\r\n".getBytes());
//        ctx.channel().writeAndFlush(buf2);
//        System.out.println("==========");

//        Thread.sleep(5000);
//        String result1 = "{\"result\":\"success\",\"msg\":\"2\"}";
//        ByteBuf buf3 = Unpooled.buffer();
//        buf.writeBytes(result1.getBytes());
//        ctx.channel().writeAndFlush(buf3);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("新的客户端链接：" + ctx.channel().id().asShortText());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开：" + ctx.channel().id().asShortText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("客户端异常：" + ctx.channel().id().asShortText());
        cause.printStackTrace();
        ctx.channel().close();
    }

}
